<?php

class Connection
{
    public $_config;
    public function __construct($config){
        $this->_config = $config;
    }
    public function getConfig()
    {
        var_dump($this->_config);
    }
}

class Registry
{
    protected static $_connection;

    /**
     * Creates a connection
     */
    protected static function _createConnection()
    {
        return new Connection(array(
            "host" => "localhost",
            "username" => "root",
            "password" => "secret",
            "dbname" => "invo"
        ));
    }

    /**
     * Creates a connection only once and returns it
     */
    public static function getConnection()
    {
        if (self::$_connection===null){
            $connection = self::_createConnection();
            self::$_connection = $connection;
        }
        return self::$_connection;
    }
}

class Person
{

    public $name;
    public $age;

    public function __construct($name, $age){
        $this->name = $name;
        $this->age = $age;
    }

    public function say(){ 
        var_dump("姓名:" . $this->name . ",年龄:" . $this->age);
    }
}   

class DI
{
    protected $_bindings = [];  //服务列表
    protected $_instances = [];    //已经实例化服务

    public function get($name, ...$args)
    {
        //先从已经实例化的列表中查找
        if(isset($this->_instances[$name])){
            return $this->_instances[$name];
        }
         
        //检测有没有注册该服务
        if(!isset($this->_bindings[$name])){
            return null;
        }

        $concrete = $this->_bindings[$name];//对象具体注册内容
         
        $obj = null;
        //匿名函数方式
        if($concrete instanceof \Closure){
            if($args){
                $obj = call_user_func_array($concrete, $args);
            }else{
                $obj = $concrete();
            }
        }
        //写入_instances列表，下次直接取回
        if($obj){
            $this->_instances[$name] = $obj;
        }
         
        return $obj;
    }

    public function set($name, $class)
    {
        if(isset($this->_instances[$name])){
            unset($this->_instances[$name]);
        }
        
        // 如果已经实例化
        if(!$class instanceof \Closure && is_object($class)){
            $this->_instances[$name] = $class;
        }else{
            $this->_bindings[$name] = $class;
        }
    }
}

$di = new DI();

$di->set('db', function(){
    return Registry::getConnection();
});

$di->set('person', function($name, $age){
    return new Person($name, $age);
});

$di->set('date', new DateTime());

$di->get('db')->getConfig();

$di->get('person', '王五', 20)->say();

var_dump($di->get('date')->format('Y-m-d H:i:s'));